#pragma once

#include<iostream>
#include<vector>
#include"Sem.hpp"
#include"Mutex.hpp"

//应该在@2加🔒
//这里抽象成是先排队再买票；还是先定好票了，再排队进入的问题
//显然@2效率更高

static const int gcap = 5;

using namespace SemModule;
using namespace MutexModule;
//typename告诉编译器某个嵌套标识符是一个类型，而非静态成员或枚举值
template<typename T>
class RingQueue
{
public:
	RingQueue(int cap = gcap)
		: _cap(cap)
		, _rp(cap)
		, _blank_sem(cap)
		, _p_step(0)
		, _data_sem(0)
		,_c_step(0)
	{
	}

	void Equeue(const T &in)
	{
		//生产者
		// _pmutex.Lock();//这里加锁和解锁？@1
		//1. 申请信号量，空位置信号量
		_blank_sem.P();
		{	//还是在这里加把锁？@2（看上）
			LockGuard Lockguard(_pmutex);
			// 2.生产
			_rq[_p_step] = in;
			// 3.更新下标
			++_p_step;
			// 4.维持环形特征
			_p_step %= _cap;
		}
		_data_sem.V();
	}

	void Pop(T* out)
	{
		//消费者
		// 1.申请信号量，数据信号量
		_data_sem.P();
		{
			LockGuard Lockguard(_cmutex);
			// 2.消费
			*out = _rq[_c_step];
			// 3.更新下标
			++_c_step;
			// 4.维持环型特性
			_c_step %= _cap;
		}
		_blank_sem.V();
	}

private:
	std::vector<T> _rq;
	int _cap;

	//生产者
	Sem _blank_sem;// 空位置
	int _p_step;
	// 消费者
	Sem _data_sem;// 数据
	int _c_step;

	// 维护多生产，多消费，要加两把锁
	// 一把让生产生产互斥；一把让消费消费互斥
	Mutex _cmutex;
	Mutex _pmutex;
};